module iicpage(clk, rst_n, addr, csen, wren, din, dout, scl, sda);
    
    input clk;
    input rst_n;
    input [15:0] addr;
    input csen;
    input wren;
    input [7:0] din;
    output reg [7:0] dout;
    output reg scl;
    inout sda;
    
    reg clk800K;
    reg clken;
    reg wrreg;
    reg sen;
    reg sreg;
    reg enreg;
    reg [2:0] ereg;
    reg [15:0] adreg;
    reg [7:0] data;
    reg [5:0] cnt1;
    reg [3:0] cnt2;
    reg [4:0] cnt3;
    reg [4:0] state;
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
                clk800K <= 0;
                cnt1 <= 0;
            end
        else
            if(cnt1<(50000000/800000/2-1))  //仿真时改为cnt1<2
                cnt1 <= cnt1 + 1;
            else
                begin
                    clk800K <= ~clk800K;
                    cnt1 <= 0;
                end
    end
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
                ereg[2] <= 0;
                adreg <= 0;
                wrreg <= 0;
                data <= 0;
            end
        else
            if(!csen)
                begin
                    ereg[2] <= ~ereg[2];
                    adreg <= addr;
                    wrreg <= wren;
                    data <= din;
                end
    end
    
    always @(posedge clk800K or negedge rst_n)
    begin
        if(!rst_n)
            begin
                enreg <= 1;
                ereg[1:0] <= 0;
            end
        else
            begin
                ereg[1] <= ereg[2];
                ereg[0] <= ereg[1];
                enreg <= ~(ereg[0]^ereg[1]);
            end
    end
    
    always @(negedge clk800K or negedge rst_n)
    begin
        if(!rst_n)
            scl <= 0;
        else
            if(clken)
                scl <= ~scl;
            else
                scl <= 0;
    end
    
    assign sda = sen ? sreg : 1'bz;
    
    always @(posedge clk800K or negedge rst_n)
    begin
        if(!rst_n)
            begin
                dout <= 0;
                sen <= 1;
                sreg <= 1;
                clken <= 0;
                cnt2 <= 0;
                cnt3 <= 0;
                state <= 0;
            end
        else
            case(state)
                0: begin
                    if(!enreg)
                        begin
                            clken <= 1;
                            state <= 1;
                        end
                    else
                        state <= 0;
                end
                1: begin
                    if(scl)
                        begin
                            sreg <= 0;
                            state <= 2;
                        end
                    else
                        state <= 1;
                end
                2: begin
                    if(!scl)
                        begin
                            sreg <= ~sreg;
                            cnt2 <= cnt2 + 1;
                            state <= 2;
                        end
                    else if(cnt2==4)
                        begin
                            cnt2 <= 0;
                            state <= 3;
                        end
                    else
                        state <= 2;
                end
                3: begin
                    if(!scl)
                        begin
                            sreg <= 0;
                            cnt2 <= cnt2 + 1;
                            state <= 3;
                        end
                    else if(cnt2==4)
                        begin
                            cnt2 <= 0;
                            state <= 4;
                        end
                    else
                        state <= 3;
                end
                4: begin
                    if(!scl)
                        begin
                            sen <= 0;
                            state <= 4;
                        end
                    else if(sda)
                        state <= 5;
                    else
                        state <= 1;
                end
                5: begin
                    if(!scl)
                        begin
                            sen <= 1;
                            sreg <= adreg[15-cnt2];
                            cnt2 <= cnt2 + 1;
                            state <= 5;
                        end
                    else if(cnt2==8)
                        begin
                            cnt2 <= 0;
                            state <= 6;
                        end
                    else
                        state <= 5;
                end
                6: begin
                    if(!scl)
                        begin
                            sen <= 0;
                            state <= 6;
                        end
                    else if(sda)
                        state <= 7;
                    else
                        state <= 1;
                end
                7: begin
                    if(!scl)
                        begin
                            sen <= 1;
                            sreg <= adreg[7-cnt2];
                            cnt2 <= cnt2 + 1;
                            state <= 7;
                        end
                    else if(cnt2==8)
                        begin
                            cnt2 <= 0;
                            state <= 8;
                        end
                    else
                        state <= 7;
                end
                8: begin
                    if(!scl)
                        begin
                            sen <= 0;
                            state <= 8;
                        end
                    else if(sda&wrreg)
                        state <= 9;
                    else if(sda&(!wrreg))
                        state <= 11;
                    else
                        state <= 1;
                end
                9: begin
                    if(!scl)
                        begin
                            sen <= 1;
                            sreg <= data[7-cnt2];
                            cnt2 <= cnt2 + 1;
                            state <= 9;
                        end
                    else if(cnt2==8)
                        begin
                            cnt2 <= 0;
                            state <= 10;
                        end
                    else
                        state <= 9;
                end
                10: begin
                    if(!scl)
                        begin
                            sen <= 0;
                            state <= 10;
                        end
                    else if(sda&(cnt3<31))
                        begin
                            cnt3 <= cnt3 + 1;
                            state <= 9;
                        end
                    else if(sda)
                        begin
                            cnt3 <= 0;
                            state <= 16;
                        end
                    else
                        state <= 1;
                end
                11: begin
                    if(!scl)
                        begin
                            sen <= 1;
                            sreg <= 1;
                            state <= 11;
                        end
                    else if(scl)
                        begin
                            sen <= 1;
                            sreg <= 0;
                            state <= 12;
                        end
                    else
                        state <= 11;
                end
                12: begin
                    if(!scl)
                        begin
                            sreg <= ~sreg;
                            cnt2 <= cnt2 + 1;
                            state <= 12;
                        end
                    else if(cnt2==4)
                        begin
                            cnt2 <= 0;
                            state <= 13;
                        end
                    else
                        state <= 12;
                end
                13: begin
                    if(!scl&(cnt2<3))
                        begin
                            sreg <= 0;
                            cnt2 <= cnt2 + 1;
                            state <= 13;
                        end
                    else if(!scl)
                        begin
                            sreg <= 1;
                            cnt2 <= cnt2 + 1;
                            state <= 13;
                        end
                    else if(cnt2==4)
                        begin
                            cnt2 <= 0;
                            state <= 14;
                        end
                    else
                        state <= 13;
                end
                14: begin
                    if(!scl)
                        begin
                            sen <= 0;
                            state <= 14;
                        end
                    else if(sda)
                        state <= 15;
                    else
                        state <= 1;
                end
                15: begin
                    if(scl&(cnt2<7))
                        begin
                            sen <= 0;
                            dout[7-cnt2] <= sda;
                            cnt2 <= cnt2 + 1;
                            state <= 15;
                        end
                    else if(scl)
                        begin
                            sen <= 0;
                            dout[7-cnt2] <= sda;
                            cnt3 <= cnt3 + 1;
                            cnt2 <= 0;
                            state <= 14;
                        end
                    else if(cnt3==31)
                        begin
                            sen <= 1;
                            sreg <= 1;
                            cnt3 <= 0;
                            state <= 16;
                        end
                    else
                        state <= 15;
                end
                16: begin
                    if(!scl)
                        begin
                            sen <= 1;
                            sreg <= 0;
                            state <= 17;
                        end
                    else
                        state <= 16;
                end
                17: begin
                    if(scl)
                        begin
                            sen <= 1;
                            sreg <= 1;
                            state <= 0;
                        end
                    else
                        state <= 17;
                end
                default: state <= 0;
            endcase
    end
    
endmodule 